﻿using System;
using System.Collections.Generic;
using System.Xml;
using SdmxMl.Common;
using SdmxMl.GenericMetadata;
using SdmxMl.Manager;
using SdmxMl.Multiplexor;
using SdmxMl.Structure;


namespace PluginMeb
{

    public class MatrixCache
    {
        #region Internal members

        private Dictionary<int, ArtefactCache> dicoMetaSet;
        private ArtefactCache SchulartCache;
        private ArtefactCache KombinationCache;
        public string AgencyId;
        #endregion

        #region Properties

        public CodeListType CltKlasseCh { get; private set; }
        public CodeListType CltAusbildForm { get; private set; }

        public CodeListType CltSchulart
        {
            get
            {
                return SchulartCache.MaintenableArtefact as CodeListType;
            }
        }

        /// <summary>Hierarchy relation between Schulart code and Ausbildung</summary>
        public HierarchicalCodelistType HclKombination
        {
            get
            {
                return KombinationCache.MaintenableArtefact as HierarchicalCodelistType;
            }
        }
        #endregion

        #region Constants

        private const string matrixId = "MEB_MX";
        private const string FULLID_KOMBINATION = "CH1_MEB+HCL_KOMBINATION+1.0";
        private const string FULLID_AUSBILD_FORM = "CH1_MEB+CL_AUSBILDUNGSFORM+1.0";
        public const string FULLID_CANTON = "CH1_RN+CL_HGDE_KT+1.0";
        private const string FULLID_BILDUNG = "CH1_MEB+CL_KLASSECH+1.0";
        private const string FULLID_SCHULART = "CH1_MEB+CL_SCHULART+1.0";

        #endregion

        #region Constructor

        public MatrixCache()
        {
            AgencyId = Mux.IsNewSmsRegistry ? "CH1" : "CH1_MEB";

            dicoMetaSet = new Dictionary<int, ArtefactCache>(30);

            // Bildungs codes
            CreateBildungs();

            // Schulart
            SchulartCache = new ArtefactCache(new ArtefactRefTyped(SdmxArtefactType.CodeLists, Mux.FullIdSmsAdapter(FULLID_SCHULART)));

            // Kombination
            KombinationCache = new ArtefactCache(new ArtefactRefTyped(SdmxArtefactType.HierarchicalCodelists, Mux.FullIdSmsAdapter(FULLID_KOMBINATION)));

            // All Ausbildung in codelist
            SmManager sm = new SmManager();
            CltAusbildForm = sm.GetArtefact(SdmxArtefactType.CodeLists, new ArtefactRefBase(Mux.FullIdSmsAdapter(FULLID_AUSBILD_FORM)), true) as CodeListType;
        }

        #endregion

        #region Bildungs for Matrix

        private void CreateBildungs()
        {
            // Bildung part
            ArtefactCache bildungCache = new ArtefactCache(new ArtefactRefTyped(SdmxArtefactType.CodeLists, Mux.FullIdSmsAdapter(FULLID_BILDUNG)));
            CltKlasseCh = bildungCache.MaintenableArtefact as CodeListType;

            // add an empty possibility
            CodeType cbEmpty = new CodeType();
            cbEmpty.Id = string.Empty;
            cbEmpty.Name.UpdateDefaultText("Empty");

            CltKlasseCh.CodeList.Insert(0, cbEmpty);
        }
        #endregion

        #region Get Matrix for Canton

        public string ComposeMatrixFullId(int cantonIndex)
        {
            return (AgencyId + "+MS_" + matrixId + "_" + cantonIndex.ToString().PadLeft(2, '0') + "+1.0");
        }

        public MetadataSetType GetMatrix(int cantonIndex)
        {
             // Do we need to load
            if (dicoMetaSet.ContainsKey(cantonIndex) == false)
            {
                string matrixFullId = ComposeMatrixFullId(cantonIndex);
                ArtefactCache ac = new ArtefactCache(new ArtefactRefTyped(SdmxArtefactType.MetadataSet, 
                    matrixFullId));
                dicoMetaSet.Add(cantonIndex, ac);
            }

            return dicoMetaSet[cantonIndex].MaintenableArtefact as MetadataSetType;
        }
        #endregion

        public void CancelMatrixReservation()
        {
            foreach (ArtefactCache mit in dicoMetaSet.Values)
                mit.CancelReservation();
            SchulartCache.CancelReservation();
            KombinationCache.CancelReservation();
        }

        public bool Reserve(int cantonIndex)
        {
            bool isUpdated = false;

            // Reserve current matrix, Schulart and Kombi hierarchy
            if (dicoMetaSet.ContainsKey(cantonIndex))
            {
                if (dicoMetaSet[cantonIndex].Reserve())
                    isUpdated = true; // needs grid reload
                SchulartCache.Reserve();
                KombinationCache.Reserve();
            }
            else 
                throw new ApplicationException("Invalid canton index given in meta cache: " + cantonIndex.ToString());
            
            return isUpdated;
        }

        public void Save(int cantonIndex, int modifFlag)
        {
            if ((modifFlag & (int)ModifType.Matrix) != 0)
            {
                if (dicoMetaSet.ContainsKey(cantonIndex))
                {
                    dicoMetaSet[cantonIndex].Persist();
                }
                else
                    throw new ApplicationException("Invalid canton index given in meta cache: " + cantonIndex.ToString());
            }
            if ((modifFlag & (int)ModifType.Schulart) != 0)
                SchulartCache.Persist();
            if ((modifFlag & (int)ModifType.Kombi) != 0)
                KombinationCache.Persist();

        }

        public void UpdateMatrixContent(int cantonIndex, MetadataSetType ms)
        {
            if (dicoMetaSet.ContainsKey(cantonIndex))
            {
                dicoMetaSet[cantonIndex].UpdateContent(ms);
            }
            else
                throw new ApplicationException("Invalid canton index given in meta cache: " + cantonIndex.ToString());
        }

        public void ReloadEditableContent(int cantonIndex, int modifFlag)
        {
            if ((modifFlag & (int)ModifType.Matrix) != 0)
            {
                if (dicoMetaSet.ContainsKey(cantonIndex))
                {
                    dicoMetaSet[cantonIndex] = new ArtefactCache(new ArtefactRefTyped(SdmxArtefactType.MetadataSet,
                    ComposeMatrixFullId(cantonIndex)));

                }
                else
                    throw new ApplicationException("Invalid canton index given in meta cache: " + cantonIndex.ToString());
            }
            // Schulart
            if ((modifFlag & (int)ModifType.Schulart) != 0)
                SchulartCache = new ArtefactCache(new ArtefactRefTyped(SdmxArtefactType.CodeLists, Mux.FullIdSmsAdapter(FULLID_SCHULART)));
            // Kombination
            if ((modifFlag & (int)ModifType.Kombi) != 0)
                KombinationCache = new ArtefactCache(new ArtefactRefTyped(SdmxArtefactType.HierarchicalCodelists, Mux.FullIdSmsAdapter(FULLID_KOMBINATION)));



        }

    }
}
